package csci5828.search;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.basic.DateConverter;
import com.thoughtworks.xstream.converters.collections.CollectionConverter;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.DomReader;

public class CityGridSearch implements Search {
	
	private static final String URL = "http://api.citygridmedia.com/content/reviews/v2/search/where";
	private final Logger logger = Logger.getLogger(getClass());
	private final XStream xstream;
	private String location;
	
	public CityGridSearch (String location) {
		this.location = location;
		xstream = new XStream(new DomDriver()); // does not require XPP3 library
		xstream.registerConverter(new CollectionConverter(xstream.getMapper()));
		xstream.alias("review", CityGridSearchResult.class);
		String[] dateFormats = new String[] { "yyyy-MM-dd", "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.SZ", "yyyy-MM-dd'T'HH:mm:ss"};
		xstream.registerConverter(new DateConverter("yyyy-MM-dd'T'HH:mm:ss", dateFormats));
	}

	@Override
	public SearchResults search(String query) {
		try {
			long start = System.currentTimeMillis();
			List<SearchResult> searchResults = toSearchResults(runQuery(query));
			Double elapsed = (System.currentTimeMillis() - start) / 1.0e3;
			return new SearchResults("CityGrid", elapsed, searchResults);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private List<SearchResult> toSearchResults (Document doc) throws XPathExpressionException {
		List <SearchResult>	searchResults = new ArrayList<SearchResult>();
		
		XPathFactory xpFactory = XPathFactory.newInstance();
		XPath xpath = xpFactory.newXPath();
		//xpath.setNamespaceContext(nsContext);
		NodeList nodeList = (NodeList) xpath.evaluate("//reviews/review", doc, XPathConstants.NODESET);
		if (nodeList != null) {
    		for (int i=0; i < nodeList.getLength(); i++) {
    			Node node = nodeList.item(i);
    			CityGridSearchResult cgsr = (CityGridSearchResult)xstream.unmarshal(new DomReader((Element)node));
    			logger.info("business="+cgsr.getBusiness_name());
    			Double nmRating = new Double(cgsr.getReview_rating());
    			nmRating = nmRating/2;
    			SearchResult searchResult  = new SearchResult(
    				cgsr.getSource(),
    				cgsr.getReview_rating(),
    				cgsr.getReview_rating(),
    				nmRating,
    				cgsr.getReview_url(),
    				cgsr.getReview_text(),
    				cgsr.getBusiness_name(),
    				0.0
    			);
    			searchResults.add(searchResult);
    		}
		}
		
		return searchResults;
	}
	
	private Document runQuery(String query) {
		Map<String, String> params = new LinkedHashMap<String, String>();
		params.put("where", this.location);
		params.put("what", query);
		params.put("publisher", "test");
		
		String requestUrl = URL + "?" + URLUtils.canonicalize(params);
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            logger.info("Retrieving URL="+requestUrl);
            Document doc = db.parse(requestUrl);
            return doc;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
	}
	
	public static void main (String[] args) {
		new CityGridSearch("80303").search("dog grooming");
	}

}
